<?php


namespace app\api\controller;

use app\api\model\ArrayPaginate;
use app\api\model\PurchaseModel;
use app\api\model\SupplierModel;
use app\api\validate\PurchaseValidate;
use app\http\GetUid;
use think\Db;
use think\db\exception\DataNotFoundException;
use think\db\exception\ModelNotFoundException;
use think\db\Query;
use think\exception\DbException;
use think\facade\Request;
use think\facade\Validate;

class SmartReplenish extends Common
{
    use ArrayPaginate;
    use GetUid;

    public function index(Request $request)
    {
        // 当选择补货方式为特定销售天数时，
        //需要输入日均销量计算周期及销售总天数
        $validate = Validate::make([
            'sales_cycle' => 'requireIf:replenish,2',
            'total_days' => 'requireIf:replenish,2',
        ]);

        if (!$validate->check($request::param())) {
            return $this->returnJson(422, $validate->getError());
        }
        // 分类
        $categoryWhere = $request::has('category', 'param', true) ? ['category', '=', $request::param('category')] : [];
        // 品牌
        $brandWhere = $request::has('brand', 'param', true) ? ['brand', '=', $request::param('brand')] : [];
        // 供应商
        $supplierWhere = $request::has('supplier', 'param', true) ? ['supplier', '=', $request::param('supplier')] : [];
        // 仓库
        $warehouseWhere = $request::has('warehouse', 'param', true)
            ? ['warehouse', '=', $request::param('warehouse')]
            : [];
        // 商品
        if ($request::has('commodity', 'param', true)) {
            // 商品
            $commodity = Db::name('commodity')->where($categoryWhere)->where($brandWhere)
                ->whereLike('name', '%' . $request::param('commodity') . '%')->select();
            $commodityWhere = function (Query $query) use ($request, $commodity) {
                $query->whereIn('commodity_id', array_map(function ($item) {
                    return $item['id'];
                }, $commodity));
            };
        } else {
            $commodity = Db::name('commodity')->where($categoryWhere)->where($brandWhere)->select();
            $commodityWhere = function (Query $query) use ($request, $commodity) {
                $query->whereIn('commodity_id', array_map(function ($item) {
                    return $item['id'];
                }, $commodity));
            };
        }
        // 采购
        $purchase = Db::name('purchase')->where($supplierWhere)->where($warehouseWhere)
            ->fetchCollection(true)->select();
        $product = \app\api\model\Product::with('commodity,stock')->where($commodityWhere)
            ->order('id', 'desc')->select();
        $pr = array_map(function ($v) use ($purchase) {
            $relation = Db::name('purchaserelation')->where('product_id', $v['id'])
                ->whereIn('pid', $purchase->column('id'))->order('id', 'desc')->select();
            $v['relation'] = array_map(function ($r) {
                $r['purchase'] = Db::name('purchase')->find($r['pid']);
                return $r;
            }, $relation);
            return $v;
        }, $product->toArray());
        // 采购关联 单品 销售关联
        $prs = array_map(function ($v) {
            $v['salerelation'] = Db::name('salerelation')->where('product_id', $v['id'])->select();
            return $v;
        }, $pr);
        // 补货方式
        if ($request::param('replenish', 1) == 2) {
            $res = $this->replenishmentToASpecificSalesDay(
                $prs,
                $request::param('sales_cycle', 15),
                $request::param('total_days')
            );
        } else {
            $res = $this->replenishmentToStockWarningLowerLimit($prs);
        }
        return $this->returnJson(
            200,
            'ok',
            $this->arrayPaginate(
                $res,
                $request::param('page', 1),
                $request::param('size', 10)
            )
        );
    }

    /**
     * 补货至特定销售天数
     * @param array $prs
     * @param $cycle
     * @param $totalDays
     * @return array
     */
    protected function replenishmentToASpecificSalesDay(array $prs, $cycle, $totalDays)
    {
        return array_map(function ($p) use ($cycle, $totalDays) {
//            dump(is_null($p['stock']));exit();
            if (is_null($p['stock'] || is_null($p['salerelation']))) {
                $p['info'] = self::getInfo();
                // 供应商汇总
                $p['info']['sum_supplier'] = array_unique(array_map(function ($r) {
                    return SupplierModel::find($r['purchase']['supplier'])['name'];
                }, $p['relation']));
            } else {
                // 供应商汇总
                $p['info']['sum_supplier'] = array_unique(array_map(function ($r) {
                    return SupplierModel::find($r['purchase']['supplier'])['name'];
                }, $p['relation']));
                // 总待入库数
                $p['info']['sum_pull_num'] = array_sum(array_map(function ($s) {
                    return $s['put_number'];
                }, $p['relation']));
                // 总待出库数
                $p['info']['sum_push_num'] = array_sum(array_map(function ($s) {
                    return $s['put_number'];
                }, $p['salerelation']));
                // 补货至特定销售天数
                // 低于预警数 实际库存低于 预警数
                $p['info']['lower_stock'] = $p['stock']['stock'] - $p['stock_lower'];
                // 近{$cycle}天日均销量 销售关联表近{$cycle}天日均销量
//                    $p['info']['averageDailySales'] = $this->averageDailySalesInThePastCycleDays($p['id'], 15);
                $p['info']['averageDailySales'] = $this->averageDailySalesInThePastCycleDays($p['id'], $cycle);
                if ($p['info']['averageDailySales']) {
                    // 支撑销售天数 当前库存按（近{$cycle}日均销量）可销售天数
                    $p['info']['supportSalesDays'] = $this->supportSalesDays($p);
                    // 建议补货量 销售关联表近{$cycle}天日均销量 *（{$totalDays} - 支撑销售天数)
                    $p['info']['replenish'] = $p['info']['averageDailySales']
                        * ($totalDays - $p['info']['supportSalesDays']);
                } else {
                    $p['info']['supportSalesDays'] = false;
                    $p['info']['replenish'] = false;
                }
            }
            return $p;
        }, $prs);
    }

    protected function supportSalesDays($p)
    {
        return round(($p['stock']['stock'] / $p['info']['averageDailySales']), 2);
    }

    /**
     * 近cycle天日均销量
     * @param int $productId
     * @param int $cycle
     * @return float|int
     */
    protected function averageDailySalesInThePastCycleDays(int $productId, $cycle = 15)
    {
        // 销售关联表近十五天日均销量
        try {
            $relations = Db::name('salerelation')->where('product_id', $productId)
                ->where('create_time', '>=', (time() - ($cycle * 24 * 60 * 60)))->fetchCollection()->select();
        } catch (DataNotFoundException $e) {
            return $e->getMessage();
        } catch (ModelNotFoundException $e) {
            return $e->getMessage();
        } catch (DbException $e) {
            return $e->getMessage();
        }
        return round((array_sum($relations->column('number')) / $cycle), 2);
    }

    /**
     * @return array
     */
    private static function getInfo()
    {
        return array_fill_keys([
            'supportSalesDays', 'replenish', 'sum_pull_num',
            'sum_push_num', 'lower_stock', 'averageDailySales'
        ], false);
    }

    /**
     * 补货至库存预警下限
     * @param array $prs
     * @return \think\response\Json
     */
    protected function replenishmentToStockWarningLowerLimit(array $prs)
    {
        $f = array_filter($prs, function ($v) {
            return !empty($v['relation']);
        });
        // 补货至库存预警下限
        return array_map(function ($p) {
            if (!($p['stock'])) {
                $p['info'] = self::getInfo();
                // 供应商汇总
                $p['info']['sum_supplier'] = array_unique(array_map(function ($r) {
                    return SupplierModel::find($r['purchase']['supplier'])['name'];
                }, $p['relation']));
            } else {
                // 补货至库存预警下限
                // 供应商汇总
                $p['info']['sum_supplier'] = array_unique(array_map(function ($r) {
                    return SupplierModel::find($r['purchase']['supplier'])['name'];
                }, $p['relation']));
                // 总待入库数
                $p['info']['sum_pull_num'] = array_sum(array_map(function ($s) {
                    return $s['put_number'];
                }, $p['relation']));
                // 低于预警数
                $p['info']['lower_stock'] = $p['stock']['stock'] - $p['stock_lower'];
                // 建议补货量
                $p['info']['replenish'] = $p['stock_lower'];
                $p['info']['sum_push_num'] = false;
                $p['info']['averageDailySales'] = false;
                $p['info']['supportSalesDays'] = false;
                if ($p['salerelation']) {
                    // 总待出库数
                    $p['info']['sum_push_num'] = array_sum(array_map(function ($s) {
                        return $s['put_number'];
                    }, $p['salerelation']));
//                    // 总可用库存
//                    $p['info']['sum_av_stock'] = $p['stock']['stock']
                    // 近15天日均销量 销售关联表近十五天日均销量
                    $p['info']['averageDailySales'] = $this->averageDailySalesInThePastCycleDays($p['id'], 15);
                    $p['info']['supportSalesDays'] = false;
                    if ($p['info']['averageDailySales']) {
                        // 支撑销售天数 当前库存按（近十五天日均销量）可销售天数
                        $p['info']['supportSalesDays'] = $this->supportSalesDays($p);;
                    }
                }
            }
            return $p;
        }, $f);
    }

    // 智能补货 根据采购单和补货数量 新建采购草稿
    public function store(Request $request, PurchaseModel $model)
    {
//        $data = $request->post();
        $oldPur = $model->findOrFail($request::param('purchase_id', ''));
        $product = \app\api\model\Product::find($request::param('product_id', ''));
        $oldPurR = Db::name('purchaserelation')
            ->where('pid', $oldPur['id'])->where('product_id', $product['id'])->find();
//        dump($oldPur);dump($product);exit();

        $data = $oldPur->toArray();
        unset($data['id']);
        $data['goods'] = [array_merge($oldPurR, $product->toArray())];
        $data['goods'][0]['put_number'] = $request::param('replenish', 0);
//        $data['goods'][0]['id'] = $product['id'];
//        $data['goods'][0]['price'] = $oldPurR['price'];
//        $data['goods'][0]['discount'] = $oldPurR['discount'];
//        $data['goods'][0]['discount_price'] = $oldPurR['discount_price'];
//        $data['goods'][0]['money'] = $oldPurR['money'];
//        $data['goods'][0]['discount_money'] = $oldPurR['discount_money'];
        $data['number'] = 'jxc' . time();//单号
        $data['uid'] = self::getUId();//制单人id
        $data['create_time'] = time();
        $data['status'] = 5;
//        $data['type1'] = 1;//1采购单
//        dump($data);exit();
        $validate = new PurchaseValidate();
        if (!$validate->check($data)) {
            return json(['code' => 404, 'msg' => $validate->getError()]);
        }
        $arr = $model->getPurchaseAdd($data);
        if (!empty($arr)) {
            return json(['code' => 200, 'msg' => '添加成功', 'list' => $arr]);
        } else {
            return json(['code' => 500, 'msg' => '添加失败', 'list' => $arr]);
        }
    }
}
